home *** CD-ROM | disk | FTP | other *** search
/ GFX Sensations 1 / Graphic Sensations - Volume 1.iso / tools / amiga / 3d_tools / irit40s.lha / Irit / cagd_lib / cagdcmps.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-30  |  16.3 KB  |  551 lines

  1. /******************************************************************************
  2. * CagdCmps.c - Composition computation (symbolic).                  *
  3. *******************************************************************************
  4. * Written by Gershon Elber, Apr. 93.                          *
  5. ******************************************************************************/
  6.  
  7. #include <string.h>
  8. #include "cagd_loc.h"
  9.  
  10. #define ZERO_SET_EPS 0.0001
  11.  
  12. static CagdCrvStruct *CagdComposeCrvCrvAux(CagdCrvStruct *Crv1,
  13.                        CagdCrvStruct *Crv2);
  14. static CagdCrvStruct *CagdComposeCrvCrvAux2(CagdCrvStruct *Crv1,
  15.                         CagdCrvStruct *Crv2);
  16. static CagdCrvStruct *CagdComposeSrfCrvAux(CagdSrfStruct *Srf,
  17.                        CagdCrvStruct *Crv);
  18. static CagdCrvStruct **CagdComputeCurvePowers(CagdCrvStruct *Crv, int Order);
  19.  
  20. /******************************************************************************
  21. * Given two curves, Crv1 and Crv2, computes the composition Crv1(Crv2(t)).    *
  22. ******************************************************************************/
  23. CagdCrvStruct *CagdComposeCrvCrv(CagdCrvStruct *Crv1, CagdCrvStruct *Crv2)
  24. {
  25.     CagdCrvStruct *CmpsCrv;
  26.     CagdRType TMax, TMin, CTMax, CTMin;
  27.  
  28.     switch (Crv1 -> GType) {
  29.     case CAGD_CBEZIER_TYPE:
  30.     case CAGD_CBSPLINE_TYPE:
  31.         break;
  32.     case CAGD_CPOWER_TYPE:
  33.         FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
  34.         break;
  35.     default:
  36.         FATAL_ERROR(CAGD_ERR_UNDEF_CRV);
  37.         break;
  38.     }
  39.  
  40.     switch (Crv2 -> GType) {
  41.     case CAGD_CBEZIER_TYPE:
  42.     case CAGD_CBSPLINE_TYPE:
  43.         break;
  44.     case CAGD_CPOWER_TYPE:
  45.         FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
  46.         break;
  47.     default:
  48.         FATAL_ERROR(CAGD_ERR_UNDEF_CRV);
  49.         break;
  50.     }
  51.  
  52.     CmpsCrv = CagdComposeCrvCrvAux(Crv1, Crv2);
  53.  
  54.     /* Now map the domain of the curve to be crv2 domain. */
  55.     CagdCrvDomain(Crv2, &TMin, &TMax);
  56.     CagdCrvDomain(CmpsCrv, &CTMin, &CTMax);
  57.     if (CmpsCrv -> GType == CAGD_CBEZIER_TYPE) {
  58.     CagdCrvStruct
  59.         *CTmp = CnvrtBezier2BsplineCrv(CmpsCrv);
  60.  
  61.     CagdCrvFree(CmpsCrv);
  62.     CmpsCrv = CTmp;
  63.     }
  64.     BspKnotAffineTrans(CmpsCrv -> KnotVector,
  65.                CmpsCrv -> Length + CmpsCrv -> Order,
  66.                TMin - CTMin,
  67.                (TMax - TMin) / (CTMax - CTMin));
  68.  
  69.     return CmpsCrv;
  70. }
  71.  
  72. /******************************************************************************
  73. * Aux. function. Subdivides Crv2 until it is a Bezier curve, invokes the      *
  74. * Bezier composition code on them, and merges them back to a complete curve.  *
  75. * At this point, curves can be either Bezier or Bspline only.              *
  76. * Curves are both assumed to have open end condition.                  *
  77. ******************************************************************************/
  78. static CagdCrvStruct *CagdComposeCrvCrvAux(CagdCrvStruct *Crv1,
  79.                        CagdCrvStruct *Crv2)
  80. {
  81.     CagdCrvStruct *CmpsCrv;
  82.  
  83.     if (Crv2 -> Length > Crv2 -> Order) {
  84.     CagdRType t;
  85.  
  86.     /* Crv2 is not a Bezier segment. Subdivide, compute for each segment */
  87.     /* and merge back.                             */
  88.     CagdCrvStruct *Crv2a, *Crv2b, *CmpsCrvA, *CmpsCrvB;
  89.  
  90.     t = Crv2 -> KnotVector[(Crv2 -> Order + Crv2 -> Length) / 2];
  91.  
  92.     Crv2a = CagdCrvSubdivAtParam(Crv2, t);
  93.     Crv2b = Crv2a -> Pnext;
  94.  
  95.     CmpsCrvA = CagdComposeCrvCrvAux(Crv1, Crv2a);
  96.     CmpsCrvB = CagdComposeCrvCrvAux(Crv1, Crv2b);
  97.     CagdCrvFree(Crv2a);
  98.     CagdCrvFree(Crv2b);
  99.  
  100.     CmpsCrv = CagdMergeCrvCrv(CmpsCrvA, CmpsCrvB);
  101.     CagdCrvFree(CmpsCrvA);
  102.     CagdCrvFree(CmpsCrvB);
  103.     }
  104.     else {
  105.         /* Crv2 is a Bezier segment - compute its composition. */
  106.         CmpsCrv = CagdComposeCrvCrvAux2(Crv1, Crv2);
  107.     }
  108.  
  109.     return CmpsCrv;    
  110. }
  111.  
  112. /******************************************************************************
  113. * Aux. function. Subdivides Crv1 until it is a Bezier curve, invokes the      *
  114. * Bezier composition code on them, and merges them back to a complete curve.  *
  115. * At this point, Crv1 is a Bezier curve, Crv2 can be either Bezier or Bspline.*
  116. * Curves are both assumed to have open end condition.                  *
  117. ******************************************************************************/
  118. static CagdCrvStruct *CagdComposeCrvCrvAux2(CagdCrvStruct *Crv1,
  119.                         CagdCrvStruct *Crv2)
  120. {
  121.     CagdRType t, TMin, TMax, CTMax, CTMin;
  122.     CagdCrvStruct *CmpsCrv;
  123.  
  124.     if (Crv1 -> Length > Crv1 -> Order) {
  125.     /* Needs to compose in pieces after subdividing Crv2 at the interior */
  126.     /* knots of Crv1, by finding where Crv2(r) = t, the interior knot.   */
  127.     CagdCrvStruct *Crv1a, *Crv1b, *Crv2a, *Crv2b, *CmpsCrvA, *CmpsCrvB;
  128.     CagdPtStruct *Pts;
  129.  
  130.     t = Crv1 -> KnotVector[(Crv1 -> Order + Crv1 -> Length) / 2];
  131.     Crv1a = CagdCrvSubdivAtParam(Crv1, t);
  132.     Crv1b = Crv1a -> Pnext;
  133.  
  134.     Pts = CagdCrvConstSet(Crv2, 1, ZERO_SET_EPS, t);
  135.     if (Pts) {
  136.         if (Pts -> Pnext != NULL)
  137.         FATAL_ERROR(CAGD_ERR_REPARAM_NOT_MONOTONE);
  138.         t = Pts -> Pt[0];
  139.         CagdPtFreeList(Pts);
  140.         Crv2a = CagdCrvSubdivAtParam(Crv2, t);
  141.         Crv2b = Crv2a -> Pnext;
  142.     }
  143.     else
  144.         Crv2a = Crv2b = NULL;
  145.  
  146.     CmpsCrvA = CagdComposeCrvCrvAux2(Crv1a, Crv2a ? Crv2a : Crv2);
  147.     CmpsCrvB = CagdComposeCrvCrvAux2(Crv1b, Crv2b ? Crv2b : Crv2);
  148.     CagdCrvFree(Crv1a);
  149.     CagdCrvFree(Crv1b);
  150.     if (Crv2a)
  151.         CagdCrvFree(Crv2a);
  152.     if (Crv2b)
  153.         CagdCrvFree(Crv2b);
  154.  
  155.     CmpsCrv = CagdMergeCrvCrv(CmpsCrvA, CmpsCrvB);
  156.     CagdCrvFree(CmpsCrvA);
  157.     CagdCrvFree(CmpsCrvB);
  158.     }
  159.     else {
  160.     /* We can compose the curves, but first make sure the domain of */
  161.     /* Crv1 is [0, 1] which is also the range of Crv2.        */
  162.     CagdCrvDomain(Crv1, &TMin, &TMax);
  163.     if (!APX_EQ(TMin, 0.0) || !APX_EQ(TMax, 1.0)) {
  164.         CagdRType
  165.         Translate = -TMin;
  166.  
  167.         Crv2 = CagdCrvCopy(Crv2);
  168.         CagdCrvTransform(Crv2, &Translate, 1.0 / (TMax - TMin));
  169.         CmpsCrv = BzrComposeCrvCrv(Crv1, Crv2);
  170.         CagdCrvFree(Crv2);
  171.     }
  172.     else
  173.         CmpsCrv = BzrComposeCrvCrv(Crv1, Crv2);
  174.  
  175.     /* Now map the domain of the curve to be crv2 domain. */
  176.     CagdCrvDomain(Crv2, &TMin, &TMax);
  177.     CagdCrvDomain(CmpsCrv, &CTMin, &CTMax);
  178.     if (CmpsCrv -> GType == CAGD_CBEZIER_TYPE) {
  179.         CagdCrvStruct
  180.         *CTmp = CnvrtBezier2BsplineCrv(CmpsCrv);
  181.  
  182.         CagdCrvFree(CmpsCrv);
  183.         CmpsCrv = CTmp;
  184.     }
  185.     BspKnotAffineTrans(CmpsCrv -> KnotVector,
  186.                CmpsCrv -> Length + CmpsCrv -> Order,
  187.                TMin - CTMin,
  188.                (TMax - TMin) / (CTMax - CTMin));
  189.     }
  190.  
  191.     return CmpsCrv;
  192. }
  193.  
  194. /******************************************************************************
  195. * Given two Bezier curves, Crv1 and Crv2, computes composition Crv1(Crv2(t)). *
  196. * See: "Freeform surfcae analysis using a hybrid of symbolic and numeric      *
  197. * computation" by Gershon Elber, PhD thesis, University of Utah, 1992.          *
  198. ******************************************************************************/
  199. CagdCrvStruct *BzrComposeCrvCrv(CagdCrvStruct *Crv1, CagdCrvStruct *Crv2)
  200. {
  201.     CagdBType
  202.     IsRational = CAGD_IS_RATIONAL_CRV(Crv1);
  203.     int i, j, k, CmpsOrder,
  204.     Order = Crv1 -> Order,
  205.     MaxCoord = CAGD_NUM_OF_PT_COORD(Crv1 -> PType);
  206.     CagdRType
  207.     Translate = 0.0;
  208.     CagdCrvStruct **Crv2Factors,
  209.         *CmpsCrv = NULL;
  210.  
  211.     if (CAGD_NUM_OF_PT_COORD(Crv2 -> PType) != 1)
  212.     FATAL_ERROR(CAGD_ERR_WRONG_PT_TYPE);
  213.  
  214.     Crv2Factors = CagdComputeCurvePowers(Crv2, Order);
  215.     CmpsCrv = BzrCrvNew(Crv2Factors[0] -> Length, Crv1 -> PType);
  216.     CmpsOrder = CmpsCrv -> Order;
  217.  
  218.     for (j = !IsRational; j <= MaxCoord; j++) {
  219.         CagdRType
  220.         *CmpsPoints = CmpsCrv -> Points[j],
  221.         *Crv1Points = Crv1 -> Points[j];
  222.  
  223.     for (i = 0; i < Order; i++) {
  224.         CagdCrvStruct
  225.         *CTmp = CagdCrvCopy(Crv2Factors[i]);
  226.         CagdRType
  227.             *CTmpPoints = CTmp -> Points[1];
  228.  
  229.         CagdCrvTransform(CTmp, &Translate, *Crv1Points++);
  230.         if (i == 0) {
  231.                CAGD_GEN_COPY(CmpsPoints, CTmpPoints,
  232.                   CmpsOrder * sizeof(CagdRType));
  233.         }
  234.         else {
  235.             for (k = 0; k < CmpsOrder; k++)
  236.                 CmpsPoints[k] += CTmpPoints[k];
  237.         }
  238.     }
  239.     }
  240.  
  241.     for (i = 0; i < Order; i++)
  242.     CagdCrvFree(Crv2Factors[i]);
  243.  
  244.     if (CAGD_IS_RATIONAL_CRV(Crv2)) {
  245.     CagdCrvStruct *CrvW, *CrvX, *CrvY, *CrvZ, *CTmp;
  246.  
  247.     CagdCrvSplitScalar(CmpsCrv, &CrvW, &CrvX, &CrvY, &CrvZ);
  248.     CTmp = CagdCrvMergeScalar(Crv2Factors[Order], CrvX, CrvY, CrvZ);
  249.     CagdCrvFree(CmpsCrv);
  250.     CmpsCrv = CTmp;
  251.  
  252.     if (CrvX)
  253.         CagdCrvFree(CrvX);
  254.     if (CrvY)
  255.         CagdCrvFree(CrvY);
  256.     if (CrvZ)
  257.         CagdCrvFree(CrvZ);
  258.     
  259.     CagdCrvFree(Crv2Factors[Order]);
  260.     }
  261.  
  262.     IritFree((VoidPtr) Crv2Factors);
  263.  
  264.     return CmpsCrv;
  265. }
  266.  
  267. /******************************************************************************
  268. * Given a curve Crv and surface Srf, computes the composition Srf(Crv(t)).    *
  269. ******************************************************************************/
  270. CagdCrvStruct *CagdComposeSrfCrv(CagdSrfStruct *Srf, CagdCrvStruct *Crv)
  271. {
  272.     CagdCrvStruct *CmpsCrv;
  273.  
  274.     switch (Srf -> GType) {
  275.     case CAGD_SBEZIER_TYPE:
  276.         break;
  277.     case CAGD_SBSPLINE_TYPE:
  278.         FATAL_ERROR(CAGD_ERR_BSPLINE_NO_SUPPORT);
  279.         break;
  280.     case CAGD_SPOWER_TYPE:
  281.         FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
  282.         break;
  283.     default:
  284.         FATAL_ERROR(CAGD_ERR_UNDEF_CRV);
  285.         break;
  286.     }
  287.  
  288.     switch (Crv -> GType) {
  289.     case CAGD_CBEZIER_TYPE:
  290.     case CAGD_CBSPLINE_TYPE:
  291.         break;
  292.     case CAGD_CPOWER_TYPE:
  293.         FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
  294.         break;
  295.     default:
  296.         FATAL_ERROR(CAGD_ERR_UNDEF_CRV);
  297.         break;
  298.     }
  299.  
  300.     CmpsCrv = CagdComposeSrfCrvAux(Srf, Crv);
  301.  
  302.     return CmpsCrv;
  303. }
  304.  
  305. /******************************************************************************
  306. * Aux. function. Subdivides Crv until it is a Bezier curve, invokes the       *
  307. * Bezier composition code on them, and merges them back to a complete curve.  *
  308. * At this point, the curve can be either Bezier or Bspline only.              *
  309. * Curve is assumed to have open end condition.                      *
  310. ******************************************************************************/
  311. static CagdCrvStruct *CagdComposeSrfCrvAux(CagdSrfStruct *Srf,
  312.                        CagdCrvStruct *Crv)
  313. {
  314.     CagdRType t, TMin, TMax;
  315.     CagdCrvStruct *CmpsCrv;
  316.  
  317.     if (Crv -> Length > Crv -> Order) {
  318.     /* Crv is not a Bezier segment. Subdivide, compute for each segment  */
  319.     /* and merge back.                             */
  320.     CagdCrvStruct *CrvA, *CrvB, *CmpsCrvA, *CmpsCrvB;
  321.  
  322.     t = Crv -> KnotVector[(Crv -> Order + Crv -> Length) / 2];
  323.  
  324.     CrvA = CagdCrvSubdivAtParam(Crv, t);
  325.     CrvB = CrvA -> Pnext;
  326.  
  327.     CmpsCrvA = CagdComposeSrfCrvAux(Srf, CrvA);
  328.     CmpsCrvB = CagdComposeSrfCrvAux(Srf, CrvB);
  329.     CagdCrvFree(CrvA);
  330.     CagdCrvFree(CrvB);
  331.  
  332.     CmpsCrv = CagdMergeCrvCrv(CmpsCrvA, CmpsCrvB);
  333.     CagdCrvFree(CmpsCrvA);
  334.     CagdCrvFree(CmpsCrvB);
  335.     }
  336.     else {
  337.         /* Crv is a Bezier segment - compute its composition. */
  338.         CmpsCrv = BzrComposeSrfCrv(Srf, Crv);
  339.  
  340.     /* Now map the domain of the composed curve to be crv's domain. */
  341.     CagdCrvDomain(Crv, &TMin, &TMax);
  342.     if (CmpsCrv -> GType == CAGD_CBEZIER_TYPE) {
  343.         CagdCrvStruct
  344.         *CTmp = CnvrtBezier2BsplineCrv(CmpsCrv);
  345.  
  346.         CagdCrvFree(CmpsCrv);
  347.         CmpsCrv = CTmp;
  348.     }
  349.     BspKnotAffineTrans(CmpsCrv -> KnotVector,
  350.                CmpsCrv -> Length + CmpsCrv -> Order,
  351.                TMin - CmpsCrv -> KnotVector[0],
  352.                TMax - TMin);
  353.     }
  354.  
  355.     return CmpsCrv;    
  356. }
  357.  
  358. /******************************************************************************
  359. * Given a Bezier curve Crv and a Bezier surface Srf, computes the composition *
  360. * Srf(Crv(t)).                                      *
  361. * See: "Freeform surfcae analysis using a hybrid of symbolic and numeric      *
  362. * computation" by Gershon Elber, PhD thesis, University of Utah, 1992.          *
  363. ******************************************************************************/
  364. CagdCrvStruct *BzrComposeSrfCrv(CagdSrfStruct *Srf, CagdCrvStruct *Crv)
  365. {
  366.     CagdBType
  367.     IsRational = CAGD_IS_RATIONAL_SRF(Srf);
  368.     int i, j, k, l, CmpsOrder,
  369.     UOrder = Srf -> UOrder,
  370.     VOrder = Srf -> VOrder,
  371.     MaxCoord = CAGD_NUM_OF_PT_COORD(Srf -> PType);
  372.     CagdRType
  373.     Translate = 0.0;
  374.     CagdCrvStruct **CrvUFactors, **CrvVFactors, *CrvW, *CrvX, *CrvY, *CrvZ,
  375.     *CrvU, *CrvV,
  376.         *CmpsCrv = NULL;
  377.  
  378.     if (CAGD_NUM_OF_PT_COORD(Crv -> PType) != 2)
  379.     FATAL_ERROR(CAGD_ERR_WRONG_PT_TYPE);
  380.     CagdCrvSplitScalar(Crv, &CrvW, &CrvX, &CrvY, &CrvZ);
  381.     CrvU = CrvW == NULL ? CagdCrvCopy(CrvX)
  382.                 : CagdCrvMergeScalar(CrvW, CrvX, NULL, NULL);
  383.     CrvV = CrvW == NULL ? CagdCrvCopy(CrvY)
  384.             : CagdCrvMergeScalar(CrvW, CrvY, NULL, NULL);
  385.     if (CrvW)
  386.     CagdCrvFree(CrvW);
  387.     CagdCrvFree(CrvX);
  388.     CagdCrvFree(CrvY);
  389.  
  390.     CrvUFactors = CagdComputeCurvePowers(CrvU, UOrder);
  391.     CrvVFactors = CagdComputeCurvePowers(CrvV, VOrder);
  392.  
  393.     CmpsCrv = BzrCrvNew(CrvUFactors[0] -> Length + 
  394.             CrvVFactors[0] -> Length - 1, Srf -> PType);
  395.     CmpsOrder = CmpsCrv -> Order;
  396.  
  397.     for (k = !IsRational; k <= MaxCoord; k++) {
  398.         CagdRType
  399.         *CmpsPoints = CmpsCrv -> Points[k],
  400.         *SPoints = Srf -> Points[k];
  401.  
  402.     for (j = 0; j < VOrder; j++) {
  403.         for (i = 0; i < UOrder; i++) {
  404.         CagdCrvStruct
  405.             *CTmp = CagdCrvMult(CrvUFactors[i], CrvVFactors[j]);
  406.         CagdRType
  407.             *CTmpPoints = CTmp -> Points[1];
  408.  
  409.         CagdCrvTransform(CTmp, &Translate, *SPoints++);
  410.  
  411.         if (i == 0 && j == 0) {
  412.             CAGD_GEN_COPY(CmpsPoints, CTmpPoints,
  413.                   CmpsOrder * sizeof(CagdRType));
  414.         }
  415.         else {
  416.             for (l = 0; l < CmpsOrder; l++)
  417.             CmpsPoints[l] += CTmpPoints[l];
  418.         }
  419.         }
  420.     }
  421.     }
  422.  
  423.     for (i = 0; i < UOrder; i++)
  424.         CagdCrvFree(CrvUFactors[i]);
  425.     for (i = 0; i < VOrder; i++)
  426.         CagdCrvFree(CrvVFactors[i]);
  427.  
  428.     if (CAGD_IS_RATIONAL_CRV(Crv)) {
  429.     CagdCrvStruct *CTmp,
  430.         *NewCrvW = CagdCrvMult(CrvUFactors[UOrder], CrvVFactors[VOrder]);
  431.  
  432.     CagdCrvSplitScalar(CmpsCrv, &CrvW, &CrvX, &CrvY, &CrvZ);
  433.     CTmp = CagdCrvMergeScalar(NewCrvW, CrvX, CrvY, CrvZ);
  434.     CagdCrvFree(NewCrvW);
  435.     CagdCrvFree(CmpsCrv);
  436.     CmpsCrv = CTmp;
  437.  
  438.     if (CrvX)
  439.         CagdCrvFree(CrvX);
  440.     if (CrvY)
  441.         CagdCrvFree(CrvY);
  442.     if (CrvZ)
  443.         CagdCrvFree(CrvZ);
  444.  
  445.     CagdCrvFree(CrvUFactors[UOrder]);
  446.     CagdCrvFree(CrvVFactors[VOrder]);
  447.     }
  448.  
  449.     IritFree((VoidPtr) CrvUFactors);
  450.     IritFree((VoidPtr) CrvVFactors);
  451.  
  452.     CagdCrvFree(CrvU);
  453.     CagdCrvFree(CrvV);
  454.  
  455.     return CmpsCrv;
  456. }
  457.  
  458. /******************************************************************************
  459. * Computes the factors of the Bernstein polynomials where t is a scalar curve.*
  460. *                                          *
  461. *   n            n              n-i         i                      *
  462. *  B (crv(t)) = ( ) (1 - crv(t))    (crv(t))                      *
  463. *   i            i                                  *
  464. *                                          *
  465. * The curve crv(t) is a scalar, possibly rational curve.              *
  466. * The constant 1 is equal to wcrv(t) if crv(t) is rational. If rational, the  *
  467. * returned vector, index Order will contain wcrv(t)^(Order-1).              *
  468. * See: "Freeform surface analysis using a hybrid of symbolic and numeric      *
  469. * computation" by Gershon Elber, PhD thesis, University of Utah, 1992.          *
  470. ******************************************************************************/
  471. static CagdCrvStruct **CagdComputeCurvePowers(CagdCrvStruct *Crv, int Order)
  472. {
  473.     CagdBType
  474.     IsRational = CAGD_IS_RATIONAL_CRV(Crv);
  475.     int i;
  476.     CagdCrvStruct *Crv_1,
  477.     **CrvFactors1_Crv = (CagdCrvStruct **)
  478.                 IritMalloc((Order + 1) * sizeof(CagdCrvStruct *)),
  479.     **CrvFactorsCrv = (CagdCrvStruct **)
  480.                 IritMalloc((Order + 1) * sizeof(CagdCrvStruct *)),
  481.     **CrvFactors = (CagdCrvStruct **)
  482.                 IritMalloc((Order + 1) * sizeof(CagdCrvStruct *));
  483.     CagdRType *Points,
  484.     Translate = 0.0;
  485.  
  486.     if (IsRational) {
  487.     CagdCrvStruct *CrvX, *CrvY, *CrvZ, *CrvW, *CTmp;
  488.  
  489.     CagdCrvSplitScalar(Crv, &CrvW, &CrvX, &CrvY, &CrvZ);
  490.     Crv_1 = CagdCrvSub(CrvW, CrvX);
  491.  
  492.     /* Set CrvFactors[Order] to CrvW(t)^(Order-1) if curve is rational. */
  493.     CrvFactors[Order] = CagdCrvCopy(CrvW);
  494.     for (i = 1; i < Order - 1; i++) {
  495.         CTmp = CagdCrvMult(CrvFactors[Order], CrvW);
  496.         CagdCrvFree(CrvFactors[Order]);
  497.         CrvFactors[Order] = CTmp;
  498.     }
  499.  
  500.     CagdCrvFree(CrvW);
  501.     CagdCrvFree(CrvX);
  502.     }
  503.     else {
  504.         Crv_1 = CagdCrvCopy(Crv);
  505.     Points = Crv_1 -> Points[1];
  506.         for (i = 0; i < Crv -> Order; i++, Points++)
  507.             *Points = 1.0 - *Points;
  508.  
  509.     CrvFactors[Order] = NULL;
  510.     }
  511.  
  512.     for (i = 0; i < Order; i++) {
  513.         if (i == 0) {
  514.             CrvFactors1_Crv[0] = NULL;
  515.             CrvFactorsCrv[0] = NULL;
  516.     }
  517.         else if (i == 1) {
  518.             CrvFactors1_Crv[1] = Crv_1;
  519.             CrvFactorsCrv[1] = CagdCrvCopy(Crv);
  520.         }
  521.         else {
  522.             CrvFactors1_Crv[i] = CagdCrvMult(CrvFactors1_Crv[i - 1], Crv_1);
  523.             CrvFactorsCrv[i] = CagdCrvMult(CrvFactorsCrv[i - 1], Crv);
  524.         }
  525.     }
  526.  
  527.     for (i = 0; i < Order; i++) {
  528.     if (i == 0) {
  529.         CrvFactors[i]= CagdCrvCopy(CrvFactors1_Crv[Order - 1]);
  530.     }
  531.     else if (i == Order - 1) {
  532.         CrvFactors[i] = CagdCrvCopy(CrvFactorsCrv[Order - 1]);
  533.     }
  534.     else {
  535.         CrvFactors[i] = CagdCrvMult(CrvFactors1_Crv[Order - 1 - i],
  536.                     CrvFactorsCrv[i]);
  537.     }
  538.     CagdCrvTransform(CrvFactors[i],
  539.              &Translate, CagdIChooseK(i, Order - 1));
  540.     }
  541.  
  542.     for (i = 1; i < Order; i++) {
  543.         CagdCrvFree(CrvFactorsCrv[i]);
  544.         CagdCrvFree(CrvFactors1_Crv[i]);
  545.     }
  546.     IritFree((VoidPtr) CrvFactorsCrv);
  547.     IritFree((VoidPtr) CrvFactors1_Crv);
  548.  
  549.     return CrvFactors;
  550. }
  551.